﻿using OpenAI;
using OpenAI.Chat;
using Spectre.Console;
using System.ClientModel;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Text;

namespace gpt
{
    public class Program
    {
        private const int MaxHistory = 20;
        private static readonly GptStock stock = new();
        private static GptModel currentModel = stock.GetDefaultModel();
        private static readonly LimitedConcurrentQueue<ChatMessage> msgs = new(MaxHistory);
        private static ChatClient client = GetClient(currentModel.Model, currentModel.EndPoint, currentModel.ApiKey);

        private static readonly Dictionary<string, Action> CommandHandlers = new()
        {
            [AICMD.Exit] = Exit,
            [AICMD.New] = NewChat,
            [AICMD.CurrentInfo] = ShowCurrentInfo,
            [AICMD.Change] = Change,
            [AICMD.Help] = CMDHandle,
            [AICMD.List] = ShowModels,
            [AICMD.Add] = AddModel,
            [AICMD.SetDefault] = SetCurrendDefault,
            [AICMD.OpenConfig] = stock.OpenGptsTxt,
        };

        private static void CMDHandle()
        {
            var i = ConsoleTools.CMDSelect();
            switch (i)
            {
                case 0:
                    ShowCurrentInfo();
                    break;
                case 1:
                    ShowCMD();
                    break;
                case 2:
                    NewChat();
                    break;
                case 3:
                    Change();
                    break;
                case 4:
                    AddModel();
                    break;
                case 5:
                    ShowModels();
                    break;
                case 6:
                    ConsoleTools.SystemSay("已返回到对话");
                    break;
                case 7:
                    SetCurrendDefault();
                    break;
                case 8:
                    stock.OpenGptsTxt();
                    break;
                case 9:
                    Exit();
                    break;
            }
        }

        static bool Generateing = false;
        static async Task Main(string[] args)
        {
            var cts = new CancellationTokenSource();
            Console.CancelKeyPress += (sender, e) =>
            {
                if (Generateing)
                {
                    e.Cancel = true; // 阻止进程直接退出
                    cts.Cancel();    // 触发取消令牌
                    ConsoleTools.SystemSay("正在停止生成...");
                }
                else
                {
                    Exit();
                }
            };

            ConsoleTools.HelloMenu(currentModel);

            while (true)
            {
                var input = ConsoleTools.ReadMultilineInput();
                if (string.IsNullOrWhiteSpace(input)) continue;

                if (input.StartsWith(AICMD.Prefix))
                {
                    if (input == AICMD.Exit) break;
                    HandleCommand(input);
                }
                else
                {
                    try
                    {
                        await Chat(input, cts.Token);
                        cts.Dispose();
                        cts = new CancellationTokenSource(); // 重置令牌以便下次使用
                    }
                    catch (OperationCanceledException)
                    {
                        ConsoleTools.SystemSay("生成已取消");
                        if (msgs.TryPeek(out var lastMsg) && lastMsg is UserChatMessage)
                        {
                            msgs.TryDequeue(out _); // 移除未完成的消息
                        }
                    }
                }
            }

            Exit();
        }

        static void SetCurrendDefault()
        {
            stock.DefaultPoint = stock.Models.IndexOf(currentModel);
            stock.SaveModels();
            ConsoleTools.SystemSay("设置成功");
        }

        private static void HandleCommand(string command)
        {
            if (CommandHandlers.TryGetValue(command, out var handler))
            {
                handler.Invoke();
            }
            else
            {
                ConsoleTools.ErrorOut($"不支持的命令，使用 {AICMD.Help} 查看帮助");
            }
        }

        public static void AddModel()
        {
            currentModel = stock.GetNewModelByConsole();
            client = GetClient(currentModel.Model, currentModel.EndPoint, currentModel.ApiKey);
            ConsoleTools.SystemSay("添加并切换成功");
        }

        public static async Task Chat(string input, CancellationToken token)
        {
            try
            {
                msgs.Enqueue(new UserChatMessage(input));

                var response = client.CompleteChatStreamingAsync(msgs, cancellationToken: token);
                var aiResponse = await ProcessStreamingResponse(response, token);

                if (!string.IsNullOrWhiteSpace(aiResponse))
                    msgs.Enqueue(new AssistantChatMessage(aiResponse));
            }
            catch (HttpRequestException ex)
            {
                ConsoleTools.ErrorOut($"API请求失败: {ex.Message}");
            }
        }

        private static async Task<string> ProcessStreamingResponse(
            AsyncCollectionResult<StreamingChatCompletionUpdate> response,
            CancellationToken token)
        {
            var aiSay = new StringBuilder();
            var panel = new Panel("").Border(BoxBorder.Rounded);

            try
            {
                AnsiConsole.Write(new Markup($"[yellow bold]{currentModel.Model}:[/]"));
                Console.WriteLine();
                Generateing = true;
                var beginResponse = false;
                var responseList = response.WithCancellation(token).ConfigureAwait(false);
                StreamingChatCompletionUpdate firstMsg = default;

                await AnsiConsole.Status()
                    .AutoRefresh(true)
                    .Spinner(Spinner.Known.Star)
                    .SpinnerStyle(Style.Parse("green bold"))
                    .StartAsync("思考中...", async ctx =>
                    {
                        await foreach (var item in response.WithCancellation(token).ConfigureAwait(false))
                        {
                            if (!beginResponse)
                            {
                                beginResponse = true;
                                ctx.Status("正在回答");
                                ctx.Spinner(Spinner.Known.Star);
                                ctx.SpinnerStyle(Style.Parse("yellow"));
                            }

                            token.ThrowIfCancellationRequested();

                            if (item.ContentUpdate.Count > 0)
                            {
                                firstMsg = item;
                                break;
                            }
                        }
                    });

                //var text = firstMsg.ContentUpdate[0].Text;
                //aiSay.Append(text);
                //AnsiConsole.Write(new Markup($"[{ConsoleColor.ChatContent}]{text.Replace("[","[[").Replace("]", "]]")}[/]"));

                await foreach (var item in response.WithCancellation(token).ConfigureAwait(false))
                {
                    if (!beginResponse)
                    {
                        beginResponse = true;
                    }

                    token.ThrowIfCancellationRequested(); // 检查是否已取消

                    if (item.ContentUpdate.Count <= 0) continue;

                    var text = item.ContentUpdate[0].Text;
                    aiSay.Append(text);
                    AnsiConsole.Write(new Markup($"[{ConsoleColor.ChatContent}]{text.Replace("[", "[[").Replace("]", "]]")}[/]"));
                }

                Console.WriteLine();
                return aiSay.ToString();
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine();
                return aiSay.ToString();
            }
            catch (Exception ex)
            {
                if (msgs.TryPeek(out var lastMsg) && lastMsg is UserChatMessage)
                {
                    msgs.TryDequeue(out _);
                }

                ConsoleTools.ErrorOut($"API请求失败: {ex.Message}");
                ConsoleTools.ErrorOut("请求异常，" + ex.Message);
                return string.Empty;
            }
            finally
            {
                Generateing = false;
            }
        }

        private static ChatClient GetClient(string model, string endPoint, string apiKey)
        {
            var key = new ApiKeyCredential(string.IsNullOrWhiteSpace(apiKey) ? "fake_api" : apiKey);
            return new ChatClient(model, key, new OpenAIClientOptions { Endpoint = new Uri(endPoint) });
        }
        public static void Exit()
        {
            ConsoleTools.SystemSay("退出程序");
            Environment.Exit(0);
        }

        /// <summary>
        /// 开启新对话
        /// </summary>
        public static void NewChat()
        {
            msgs.Clear();
            AnsiConsole.Clear();
            ConsoleTools.SystemSay($"===================》已经开启新对话《===================");
        }

        public static void ShowCurrentInfo()
        {
            ConsoleTools.SystemSayNoFormat($"当前模型：[{ConsoleColor.Content}]{currentModel.Model.Replace("[","[[").Replace("]","]]")}[/]");
            ConsoleTools.SystemSayNoFormat($"当前上下文：[{ConsoleColor.Content}]{msgs.Count}[/]");
            ConsoleTools.SystemSayNoFormat($"当前总字符数：[{ConsoleColor.Content}]{msgs.Sum(m => m.Content[0].Text.Length)}[/]");
            Console.WriteLine();
        }

        public static void Change()
        {
            if (stock.Models == default || stock.Models.Count == 0)
            {
                currentModel = stock.GetDefaultModel();
                return;
            }

            var items = stock.Models.Select(m => $"{m.Model} --- {m.ApiKey}").ToList();
            var fruit = AnsiConsole.Prompt(
               new SelectionPrompt<string>()
               .Title($"[{ConsoleColor.System}]模型列表[/]")
               .PageSize(10)
               .MoreChoicesText($"[{ConsoleColor.System}](上下移动光标以展示很多选择)[/]")
               .AddChoices(items));
            var modelIndex = items.IndexOf(fruit);
            currentModel = stock.Models[modelIndex];
            client = GetClient(currentModel.Model, currentModel.EndPoint, currentModel.ApiKey);
            ConsoleTools.SystemSay("切换成功");
            ShowCurrentInfo();
        }

        public static void ShowCMD()
        {
            var table = new Table();

            table.AddColumn("命令");
            table.AddColumn("作用");

            table.AddRow(AICMD.Help, "进入帮助菜单");
            table.AddRow(AICMD.CurrentInfo, "展示当前信息");
            table.AddRow(AICMD.New, "开启新对话");
            table.AddRow(AICMD.Change, "切换模型");
            table.AddRow(AICMD.Add, "添加模型");
            table.AddRow(AICMD.List, "展示模型列表");
            table.AddRow(AICMD.OpenConfig, "打开配置文件");
            table.AddRow(AICMD.Exit, "退出");

            AnsiConsole.Write(table);
        }

        public static void ShowModels()
        {
            ConsoleTools.SystemSay($"配置文件地址：{Path.GetFullPath(GptStock.StockPath)}");
            var table = new Table();

            table.AddColumn("序号");
            table.AddColumn("模型");
            table.AddColumn("API地址");
            table.AddColumn("其它");

            for (var i = 0; i < stock.Models.Count; i++)
            {
                string addString = string.Empty;

                if (currentModel == stock.Models[i]) addString += "(当前)";
                if (stock.Models[stock.DefaultPoint] == stock.Models[i]) addString += "(默认)";

                table.AddRow((i + 1).ToString(), stock.Models[i].Model, stock.Models[i].EndPoint, addString);
            }

            AnsiConsole.Write(table);
        }


    }

    public class LimitedConcurrentQueue<T> : ConcurrentQueue<T>
    {
        private readonly int _maxSize;
        public LimitedConcurrentQueue(int maxSize) => _maxSize = maxSize;

        public new void Enqueue(T item)
        {
            base.Enqueue(item);
            while (Count > _maxSize) TryDequeue(out _);
        }
    }


    static class AICMD
    {

        public const string Logo = @"
 __   ___       __   ___       __ 
/ _` |__  |\ | / _` |__  |\ | /__`
\__> |___ | \| \__> |___ | \| .__/
                                   
";

        public const string Prefix = "--";

        /// <summary>
        /// 退出
        /// </summary>
        public const string Exit = Prefix + "exit";

        /// <summary>
        /// 更改配置
        /// </summary>
        public const string Change = Prefix + "change";

        /// <summary>
        /// 开始新对话
        /// </summary>
        public const string New = Prefix + "new";

        /// <summary>
        /// 帮助
        /// </summary>
        public const string Help = Prefix + "help";

        /// <summary>
        /// 当前信息
        /// </summary>
        public const string CurrentInfo = Prefix + "info";

        /// <summary>
        /// 添加模型
        /// </summary>
        public const string Add = Prefix + "add";

        /// <summary>
        /// 展示模型列表
        /// </summary>
        public const string List = Prefix + "list";

        /// <summary>
        /// 将当前模型设置为默认
        /// </summary>
        public const string SetDefault = Prefix + "setDefault";

        /// <summary>
        /// 打开配置文件
        /// </summary>
        public const string OpenConfig = Prefix + "cfg";
    }
}
